#include "ffttest.h"
#include <QDebug>
#include "event.h"
#include "eventid.h"
#include "application.h"
#include <QPointF>
#include "curve.h"

#define SOURCE_DATA_TYPE_LINEAR     0
#define SOURCE_DATA_TYPE_SIN        1
#define SOURCE_DATA_TYPE_SIN_MIX    2

//#define SOURCE_DATA_TYPE (SOURCE_DATA_TYPE_LINEAR)
//#define SOURCE_DATA_TYPE (SOURCE_DATA_TYPE_SIN)
#define SOURCE_DATA_TYPE (SOURCE_DATA_TYPE_SIN_MIX)


FFTTest::FFTTest()
{
    //Creating sample values
    createSamples();

    qDebug("Samples before transformation:\n");
    print(0, samples, FFT_BUFFER_SIZE);
}

int FFTTest::test1()
{
    //Setting a fixed size for the transformation
    if(transformer.setSize(FFT_BUFFER_SIZE) == QFourierTransformer::VariableSize)
    {
        qDebug("This size is not a default fixed size of QRealFourier. Using a variable size instead.\n");
    }
    else if(transformer.setSize(FFT_BUFFER_SIZE) == QFourierTransformer::InvalidSize)
    {
        qDebug("Invalid FFT size.\n");
        return -1;
    }

    transformer.forwardTransform(samples, fft);

    print(1, fft, FFT_BUFFER_SIZE);

    transformer.inverseTransform(fft, samples);

    qDebug("Samples after transformation and before rescaling:\n");
    print(2, samples, FFT_BUFFER_SIZE);

    transformer.rescale(samples);
    qDebug("Samples after rescaling:\n");
    print(3, samples, FFT_BUFFER_SIZE);

    return 0;
}

int FFTTest::test2()
{
    QStringList functions = transformer.windowFunctions();
    qDebug("The following window functions are available:\n");
    for(int i = 0; i < functions.size(); ++i)
    {
        qDebug() << QString::number(i + 1) + ". " + functions[i] + "\n";
    }

    qDebug("Samples before transformation:\n");
    print(0, samples, FFT_BUFFER_SIZE);

    //Setting a fixed size for the transformation
    if(transformer.setSize(FFT_BUFFER_SIZE) == QFourierTransformer::VariableSize)
    {
        qDebug("This size is not a default fixed size of QRealFourier. Using a variable size instead.\n");
    }
    else if(transformer.setSize(FFT_BUFFER_SIZE) == QFourierTransformer::InvalidSize)
    {
        qDebug("Invalid FFT size.\n");
        return -1;
    }

    if(!transformer.setWindowFunction("Hamming"))
    {
        qDebug("Could not find this window function. Defaulting to the previous one.\n");
    }

    transformer.forwardTransform(samples, fft);
    print(1, fft, FFT_BUFFER_SIZE);
    transformer.inverseTransform(fft, samples);

    qDebug("Samples after transformation and before rescaling:\n");
    print(2, samples, FFT_BUFFER_SIZE);

    transformer.rescale(samples);
    qDebug("Samples after rescaling:\n");
    print(3, samples, FFT_BUFFER_SIZE);

    return 0;
}

int FFTTest::test3()
{
    //Setting a fixed size for the transformation
    if(transformer.setSize(FFT_BUFFER_SIZE) == QFourierTransformer::VariableSize)
    {
        qDebug("This size is not a default fixed size of QRealFourier. Using a variable size instead.\n");
    }
    else if(transformer.setSize(FFT_BUFFER_SIZE) == QFourierTransformer::InvalidSize)
    {
        qDebug("Invalid FFT size.\n");
        return -1;
    }

    transformer.forwardTransform(samples, fft);
    print(1, fft, FFT_BUFFER_SIZE);
    transformer.inverseTransform(fft, samples);

    qDebug("Samples after transformation and before conjugation and rescaling:\n");
    print(2, samples, FFT_BUFFER_SIZE);

    transformer.conjugate(samples);
    qDebug("Samples after conjugation and before rescaling:\n");
    print(3, samples, FFT_BUFFER_SIZE);

    transformer.rescale(samples);
    qDebug("Samples after rescaling:\n");
    print(4, samples, FFT_BUFFER_SIZE);

    return 0;
}

void FFTTest::print(int num, float values[], int size)
{
    QVariant var;
    PlotXYParameter parameter;

    for(int i = 0; i < size; ++i)
    {
        parameter.num = num;
        parameter.x = i;
        parameter.y = values[i];
        var.setValue(parameter);
        plotXY(var);
    }
}

void FFTTest::plotXY(QVariant var)
{
    CustomEvent event((QEvent::Type)EV_CurveTest);
    event.var.setValue(var);
    Application::getInstance()->publish(&event);
}

void FFTTest::createSamples()
{
#if (SOURCE_DATA_TYPE == SOURCE_DATA_TYPE_LINEAR)
    for(int i = 0; i < FFT_BUFFER_SIZE; ++i)
    {
        samples[i] = i / float(FFT_BUFFER_SIZE);
    }
#elif (SOURCE_DATA_TYPE == SOURCE_DATA_TYPE_SIN)
    for(int i = 0; i < FFT_BUFFER_SIZE; ++i)
    {
        samples[i] = sin(i / float(FFT_BUFFER_SIZE) * 2 * M_PI);
    }
#elif (SOURCE_DATA_TYPE == SOURCE_DATA_TYPE_SIN_MIX)
    for(int i = 0; i < FFT_BUFFER_SIZE; ++i)
    {
        samples[i] = sin(i / float(FFT_BUFFER_SIZE) * 2 * M_PI);
        samples[i] += sin(i / float(FFT_BUFFER_SIZE) * 4 * M_PI);
        samples[i] += sin(i / float(FFT_BUFFER_SIZE) * 8 * M_PI);
    }
#endif
}
